<?php
/**
 * Base model class. Provides functionality to get list of records, build pagings, delete & edit record.
 * Uses Zend_Db_Table_Adstract class as parent. 
 * 
 * @author Konstantin Shamko <konstantin.shamko@gmail.com> 
 * @version 0.0.1
 * @copyright  Copyright (c) 2009 Konstantin Shamko
 * @category VaselinEngine
 * @package Bel Classes
 * @license  New BSD License
 *
 */
abstract class Bel_Model_Abstract extends Zend_Db_Table_Abstract {
	/**
	 * DB adapter object
	 *
	 * @var Zend_Db_Adapter_Abstract
	 */
	protected $_db;
	
	/**
	 * Zend_Db_Select object
	 *
	 * @var Zend_Db_Select
	 */
	private $_select;
	
	/**
	 * Table name
	 *
	 * @var string
	 */
	protected $_name;
	
	/**
	 * Paging object
	 *
	 * @var Zend_Paginator
	 */
	private $_paging;
	
	/**
	 * Quantity of items to show on page. If 0 then all 
	 * records will be return
	 *
	 * @var int
	 */
	protected $_items_on_page = 0;
	
	/**
	 * Defines name of method to generate select query for getAll()
	 *
	 * @var string
	 */
	private $_selectMethod = '_selectQuery';
	
	/**
	 * Constructor.
	 *
	 * Supported params for $config are:
	 * - db              = user-supplied instance of database connector,
	 *                     or key name of registry instance.
	 * - name            = table name.
	 * - primary         = string or array of primary key(s).
	 * - rowClass        = row class name.
	 * - rowsetClass     = rowset class name.
	 * - referenceMap    = array structure to declare relationship
	 *                     to parent tables.
	 * - dependentTables = array of child tables.
	 * - metadataCache   = cache for information from adapter describeTable().
	 *
	 * @param  mixed $config Array of user-specified config options, or just the Db Adapter.
	 * @return void
	 */	
	public function __construct($array=array()) {
		$this->_db = Zend_Registry::get ( 'db' );
		self::setDefaultAdapter ( $this->_db );
		parent::__construct ( $array );
	}
		
	/**
	 * Method to get data from a table.
	 *
	 * @param string $where - where clause
	 * @param string $order - order clause
	 * @param int $page - page number to select
	 * @return array - array with stdObjects
	 */
	public function getAll($where = NULL, $order = NULL, $page = 1){
		 $select = $this->{$this->_selectMethod}();//_selectQuery();
		 
		 if($where){
		 	$select->where($where);		 	
		 }
		 
		 if($order){
		 	$select->reset('order')->order($order);		 	
		 }	
		 
		 $dataset = NULL;
		 
		 if($this->_items_on_page){
		 	$this->_setPaging($select,$page);
		 	$dataset = $this->_getAllByPage($page);	
		 }else{
		 	$dataset = $this->_db->query($select)->fetchAll();
		 }
		 
		 return $dataset;
	}
	
	/**
	 * Sets name of the method to generate select query for getAll()
	 *
	 * @param string $methodName
	 */
	public function setSelectMethod($methodName){
		$this->_selectMethod = $methodName;
	}
	
	/**
	 * Returns entry by primary key value
	 *
	 * @param integer $id - primary key value
	 * @return Zend_Db_Table_Row | false
	 */
	public function getEntryById($id) {
		if (($row = $this->find ( $id )->current ())) {
			return $row;
		} else {
			return false;
		}
	}
	
	/**
	 * Returns paging object
	 *
	 * @param string $url - url to use in paging control
	 * @return array
	 */
	public function getPaging($url = NULL){
		if($this->_paging){
			$paging = $this->_paging->getPages();
			$paging->url = $url;
			return $paging;
		}
		return NULL;
	} 
	
	/**
	 * Set quantity of items to return after getAll method
	 *
	 * @param int $items_on_page
	 */
	public function setItemsOnPage($items_on_page){
		$this->_items_on_page = $items_on_page;
	}
	
	/**
	 * Get quantity of items to return after getAll method
	 *
	 * @return  int $items_on_page
	 */
	public function getItemsOnPage(){
		return $this->_items_on_page;
	}
			
	/**
	 * Return table's primary key field name
	 *
	 * @return string
	 */
	public function getIdCol() {
		if (isset ( $this->_primary [0] )) {
			return $this->_primary [0];
		} elseif (isset ( $this->_primary [1] )) {
			return $this->_primary [1];
		}	
	}
		
	/**
	 * Adds entry into a db
	 *
	 * @param array $data_to_add - associative array (key - name of a table field, value - field value)
	 * @return int - last inserted entry primary key
	 */
	public function addEntry($data_to_add) {
		$row = $this->createRow ( $data_to_add );
		return $row->save ();
	}
		
	/**
	 * Deletes entry by primary key value
	 *
	 * @param int $id - primary key value
	 * @return int - the number of rows deleted.
	 */
	public function deleteEntryById($id) {
		return $this->find ( $id )->current ()->delete ();
	}	
	
	/**
	 * Deletes entries by array of primary keys values
	 *
	 * @param array $ids - array of ints
	 * @return int - number of deleted rows
	 */
	public function bulkDeleteById($ids){
		if(count($ids)){
			return $this->delete($this->getIdCol().' IN ('.implode(',',$ids).')');
		}
		return 0;
	}
	
	/**
	 * Updates an entry
	 *
	 * @param array $request - associative array (key - name of a table field, value - field value)
	 * @return int - number of affected rows
	 */
	public function updateEntry($request) {
		$prep_request = $this->_prepareRequest ( $request );
		return $this->update ( $prep_request ['data'], $prep_request ['where'] );
	}
	
	/**
	 * Is used in getAll method. Returns select query. Override this method 
	 * in ancestor class to set another query
	 *
	 * @return Zend_Db_Select object
	 */
	protected function _selectQuery(){
		$select = $this->_select = $this->_db->select()->from($this->_name);
		return $select;
	}
	
	/**
	 * Initialize Zend_Paginator. Is user in getAll method
	 *
	 * @param Zend_Db_Select $select
	 * @param int $page - curreny page to return data from
	 */
	private function _setPaging(Zend_Db_Select $select,$page){
		$this->_paging = new Zend_Paginator(new Zend_Paginator_Adapter_DbSelect($select));
		$this->_paging->setCurrentPageNumber($page);
		$this->_paging->setItemCountPerPage($this->_items_on_page);
	}
	
	/**
	 * Return data set according to current page numper. Is used in getAll method
	 *
	 * @param int $page - current page number
	 * @return array
	 */
	private function _getAllByPage($page){
		return $this->_paging->getItemsByPage($page);
	}
	
	/**
	 * Gets formatted info about table
	 *
	 * @return array - info about table
	 */
	private function _getTableInfo() {
		$tabledata ['cols'] = $this->info ( 'cols' );
		
		$index = array_search ( $this->_primary [1], $tabledata ['cols'] );
		unset ( $tabledata ['cols'] [$index] );
		return $tabledata;
	}
		
	/**
	 * Prepares request for entry update
	 *
	 * @param array $request - associative array (key - name of a table field, value - field value)
	 * @return array - prepared request 
	 */
	protected function _prepareRequest($request) {
		$tabledata = $this->_getTableInfo ();
		foreach ( $tabledata ['cols'] as $col ) {
			$data [$col] = (isset ( $request [$col] )) ? $request [$col] : new Zend_Db_Expr ( $col );
		}
		$where = $this->getAdapter ()->quoteInto ( $this->_primary [1] . ' = ?', $request [$this->_primary [1]] );
		return array ('data' => $data, 'where' => $where );
	}	
}